其他
有赞移动性能监控平台(一)
点击关注“有赞coder”
获取更多技术干货哦~
部门:零售移动
前言
随着移动端业务复杂度的提升,开发同学在编写业务的时候往往容易忽略性能问题,虽然有赞移动端自研了 APM ,但是 APM 采集的都是线上的数据,无法在 QA 与开发阶段提前发现问题,为了保障软件的稳定性,需要补齐线下监控能力,避免性能问题上线对商家经营过程造成影响。
一、架构设计
整体基于 APM 现有框架迭代线下监控能力,并在端上开发 AWACS 可视化工具,通过全局悬浮窗,并结合提醒能力(弹窗与 Toast 提示)实时通知测试人员进行问题查看,同时后台也会定时分析测试环境采集的性能数据,进行管理与分配。
QA 同学基于 Appium 补齐了 UI 主流程 case ,通过自动化测试最大程度确保每次应用发版的稳定。而设备自动化回归流程可以与线下监控完美的结合起来,首先每个版本可以确保运行在同一款设备上,其次每个版本运行的主流程用例基本上保持一致,这样就为应用“前后”版本性能数据分析对比提供了两个参照条件。性能问题上报后,除了微信Robot通知相关干系人解决问题外,还基于移动端 mPaaS 搭建了问题管理与分配平台,便于跟进与追踪。
二、监控指标分析
2.1 阶段数据
2.1.1 方法耗时分析
原理
分析详情
2.1.2 网络状况分析
原理
public Response intercept(Chain chain) throws IOException {
Request request = chain.request();
Response response = null;
String url = getRequestUrl(request.url());
if (!TextUtils.isEmpty(url)) {
AppSegmentCache.INSTANCE.setRequestStart(url);
long startNs = System.nanoTime();
try {
response = chain.proceed(request);
} catch (Exception e) {
throw e;
}
long tookMs = TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - startNs);
AppSegmentCache.INSTANCE.setRequestEnd(url, tookMs);
}
return chain.proceed(request);
}
分析详情
2.2 流量
2.2.1 原理
OkHttpHook
internal object OkHttpHook {
@JvmField
public val globalNetworkInterceptor = Interceptor { chain ->
... ...
// 计算repsonse length(流量大小)
// 读取response content(如果是gzip需要解压)
// 流量内容写入文件中
val fileUrl = File(file, URLEncoder.encode(SimpleDateFormat("yyyy-MM-dd-HH:mm:ss-SSS").format(Date()) + "-" + netPackInfo.url))
fileUrl.writeText(netPackInfo.toString())
... ...
}
HttpUrlConnectHook
public object HttpUrlConnectHook {
@JvmStatic
fun proxy(httpUrlConnection: URLConnection): URLConnection {
try {
return hookOkHttpURLConnection(httpUrlConnection)
} catch (e: Exception) {
e.printStackTrace()
}
return urlConnection
}
}
@Throws(Exception::class)
private fun hookOkHttpURLConnection(httpUrlConnection: URLConnection): URLConnection {
val builder = OkHttpClient.Builder()
val mClient = builder
.retryOnConnectionFailure(true)
... ...
.build()
val strUrl = httpUrlConnection.url.toString()
val url = URL(strUrl)
val protocol = url.protocol.toLowerCase(Locale.ROOT)
if (protocol.startWith("http", ignoreCase = true)) {
return HttpUrlFactory.OkHttpURLConnection(url, mClient)
} else urlConnection
}
2.2.2 分析详情
2.3 页面耗时
2.3.1 原理
页面监控开始时机
public void watchActivity(Activity activity) {
watchWithMonitorView(activity.getClass().getName(), activity.getWindow().getDecorView());
... ...
if (activity instanceof android.support.v4.app.FragmentActivity) {
((FragmentActivity) activity).getSupportFragmentManager().registerFragmentLifecycleCallbacks(new FragmentLifecycleCallbacks() {
public void onFragmentViewCreated(android.support.v4.app.FragmentManager fm, final android.support.v4.app.Fragment f, View v,
Bundle savedInstanceState) {
watchWithMonitorView(f.getClass().getName(), v);
}
}), true);
}
... ...
}
页面监控结束时机
public void watchWithMonitorView(final String className, final View view) {
final long startTime = System.currentTimeMillis();
final WeakReference<View> viewWeakReference = new WeakReference<>(view);
final ViewTreeObserver.OnDrawListener onDrawListener = new ViewTreeObserver.OnDrawListener() {
Boolean first = true;
@Override
public void onDraw() {
if (startTime != 0 && first && viewWeakReference.get() != null) {
... ...
}
};
view.getViewTreeObserver().addOnDrawListener(onDrawListener);
}
2.3.2 分析详情
三、后台问题分析
分析工作流程(阶段数据分析举例):
四、线下AWACS工具
五、问题管理与分配平台
5.1 问题列表
5.2 问题详情
六、未来规划
拓展阅读:
有赞移动 iOS 组件化(模块化)架构设计实践 有赞零售移动端收银商品实践 聊聊UI标准化 有赞零售 App 离线切换技术方案 有赞 Android 编译进阶之路——全量编译提效方案 有赞iOS精准测试实践 有赞 Android 编译进阶之路 —— 增量编译提效方案Savitar 有赞iOS-基于二进制的编译提效策略
Vol.370